import { gfx, RenderData, spriteAssembler, UITransform, v3, Vec2, Vec3, __private } from "cc";
import { PageRender } from "./PageRender";

export type IBatcher = __private._cocos_2d_renderer_i_batcher__IBatcher;
export type TextureBase = __private._cocos_core_assets_texture_base__TextureBase;

export const gfxAttribute = gfx.Attribute;
export const gfxAttributeName = gfx.AttributeName;
export const gfxFormat = gfx.Format;

const vfmtPosUvColorFront = [
    new gfxAttribute(gfxAttributeName.ATTR_POSITION, gfxFormat.RGB32F),
    new gfxAttribute(gfxAttributeName.ATTR_TEX_COORD, gfxFormat.RG32F),
    new gfxAttribute(gfxAttributeName.ATTR_COLOR, gfxFormat.RGBA32F),
    new gfxAttribute("a_isFront", gfxFormat.R32F)
];

export default class PageEffectAssembler {
    private m_VertexCount = 4;
    private m_IndiceCount = 6;
    private m_FloatsPerVertex = 9;

    private m_ColorOffset = 5;

    private m_Vec0: Vec3 = v3();

    constructor(sprite: PageRender) {
        const segmentCount = sprite.pointsCount - 1;
        this.m_VertexCount *= segmentCount;
        this.m_IndiceCount *= segmentCount;
        this.m_FloatsPerVertex = 10;
        const data = this.createData(this.m_VertexCount, this.m_IndiceCount);
        sprite.initData(data);
    }

    public updateRenderData(sprite: PageRender) {
        const pointList = sprite.getPointList();
        const pointNum = pointList.length;
        if (pointNum < 2) return;

        const uiTransform = sprite.uiTransform;
        const height = uiTransform.height;
        const width = uiTransform.width;
        const v0 = this.m_Vec0;
        sprite.node.getWorldPosition(v0);
        const posX = - width * uiTransform.anchorX + v0.x;
        const posY = - height * uiTransform.anchorY + v0.y;

        const gapU = 1 / (pointNum - 1);
        let lastU = 0;
        let nextU = 0;

        const renderData = sprite.renderData;
        const vData = renderData.chunk.vb;
        const floatsPerVert = this.m_FloatsPerVertex;

        // 写 vData 时的下标
        let dstOffset = 0;
        for (let i = 1; i < pointNum; i++) {
            let lastPoint = pointList[i - 1];
            let nextPoint = pointList[i];
            nextU = lastU + gapU;

            // 顶点和质点一一对应
            // 顶点数据写入vData
            dstOffset = floatsPerVert * (i - 1) * 4;
            vData[dstOffset] = posX + lastPoint.x;
            vData[dstOffset + 1] = posY + lastPoint.y;
            vData[dstOffset + 2] = 0;
            vData[dstOffset + 3] = lastU;
            vData[dstOffset + 4] = 1;
            dstOffset += floatsPerVert;

            vData[dstOffset] = posX + nextPoint.x;
            vData[dstOffset + 1] = posY + nextPoint.y;
            vData[dstOffset + 2] = 0;
            vData[dstOffset + 3] = nextU;
            vData[dstOffset + 4] = 1;
            dstOffset += floatsPerVert;

            vData[dstOffset] = posX + lastPoint.x;
            vData[dstOffset + 1] = posY + height + lastPoint.y;
            vData[dstOffset + 2] = 0;
            vData[dstOffset + 3] = lastU;
            vData[dstOffset + 4] = 0;
            dstOffset += floatsPerVert;

            vData[dstOffset] = posX + nextPoint.x;
            vData[dstOffset + 1] = posY + height + nextPoint.y;
            vData[dstOffset + 2] = 0;
            vData[dstOffset + 3] = nextU;
            vData[dstOffset + 4] = 0;

            lastU = nextU;
        }

        this.updateIsFront(sprite, 9);
    }

    public fillBuffers(sprite: PageRender, renderer: IBatcher) {
        if (sprite === null) return;
        this.initIData(sprite);
    }

    public updateIsFront(sprite: PageRender, dataOffset: number) {
        const renderData = sprite.renderData;
        const vData = renderData.chunk.vb;
        const floatsPerVert = this.m_FloatsPerVertex;
        let index = 0;
        for (let i = 0, n = this.m_VertexCount; i < n; ++i) {
            index = i * floatsPerVert;
            const isFirstVert = i % 2 === 0;
            const firstVertX = isFirstVert ? vData[index] : vData[index - floatsPerVert];
            const secondVertX = isFirstVert ? vData[index + floatsPerVert] : vData[index];
            const isFront = firstVertX < secondVertX ? 1.0 : 0.0;
            vData[index + dataOffset] = isFront;
        }
    }

    private createData(vCount: number, iCount: number) {
        const data = RenderData.add(vfmtPosUvColorFront);
        data.resize(vCount, iCount);
        return data;
    }

    private initIData(sprite: PageRender) {
        const data = sprite.renderData;
        const chunk = data.chunk;
        const bid = chunk.bufferId;
        const vid = chunk.vertexOffset;
        const meshBuffer = chunk.vertexAccessor.getMeshBuffer(bid);
        const ib = chunk.vertexAccessor.getIndexBuffer(bid);
        let indexOffset = meshBuffer.indexOffset;
        let count = this.m_IndiceCount / 6;
        for (let i = 0; i < count; i++) {
            let vertextID = vid + i * 4;
            ib[indexOffset++] = vertextID;
            ib[indexOffset++] = vertextID + 1;
            ib[indexOffset++] = vertextID + 2;
            ib[indexOffset++] = vertextID + 1;
            ib[indexOffset++] = vertextID + 3;
            ib[indexOffset++] = vertextID + 2;
        }
        meshBuffer.indexOffset = indexOffset;
    }
}